```vue
<template>
  <div class="container dark-theme" @click="closeMenuOnClickOutside">
    <!-- 头部导航栏 -->
    <div class="header">
      <div class="logo">“沈誉通”信用生活综合系统</div>
      <div class="nav">
        <!-- <router-link to="/home">首页</router-link> -->
        <router-link to="/credit-life">信用生活</router-link>
        <router-link to="/credit-business">信用商业</router-link>
        <router-link to="/behavior">亲社会行为</router-link>
        <router-link to="/news">新闻资讯</router-link>
        <router-link to="/credit-management">信用管理</router-link>
      </div>
      <div class="user-menu" ref="userMenu">
        <div class="avatar-box">
          <img
            :src="user.icon || defaultIcon"
            class="avatar"
            alt="用户头像"
            @click.stop="toggleMenu"
            @error="handleImageError"
          />
        </div>
        <div v-if="isMenuOpen" class="dropdown-menu">
          <div class="menu-item" @click="goToProfile">个人信息</div>
          <div class="menu-item" @click="logout">退出登录</div>
        </div>
      </div>
    </div>

    <div class="screen">
      <div class="right-section">
        <div class="section-title">系统通知</div>
        <div v-if="newss.length === 0 && !isReachBottom" class="loading">加载中...</div>
        <div class="news-list" @scroll="onScroll">
          <div v-for="news in newss" :key="news.id" class="news-item" @click="goToNewsDetail(news.id)">
            <img :src="news.img || defaultIcon" alt="新闻图片" @error="handleImageError" />
            <div class="news-content">
              <h3>{{ news.title || '无标题' }}</h3>
              <p>{{ news.content || '无内容' }}</p>
              <div class="publisher-info">
                <div class="avatar-publisher-box">
                  <img
                    :src="news.icon || defaultIcon"
                    class="avatar"
                    alt="发布者头像"
                    @error="handleImageError"
                  />
                </div>
                <span class="publisher-name">{{ news.name || '未知用户' }}</span>
              </div>
            </div>
          </div>
          <div v-if="isReachBottom" class="loading">加载更多...</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios';
import Vue from 'vue';

// Axios 请求拦截器：添加 JWT Token
axios.interceptors.request.use(
  (config) => {
    const token = window.sessionStorage.getItem('token') || localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

export default {
  name: 'News',
  data() {
    return {
      isReachBottom: false,
      newss: [],
      current: 1,
      user: { id: null, icon: '' },
      isMenuOpen: false,
      defaultIcon: 'https://via.placeholder.com/120', // 默认图片
      imageBaseUrl: 'http://localhost:8089',
    };
  },
  created() {
    this.queryUser();
    this.queryHotNewsScroll();
  },
  methods: {
    formatImageUrl(imagePath) {
      if (!imagePath) return this.defaultIcon;
      if (imagePath.startsWith('http')) return imagePath;
      return `${this.imageBaseUrl}${imagePath}`;
    },
    async queryHotNewsScroll() {
      if (this.isReachBottom) return;
      this.isReachBottom = true;

      try {
        const userId = this.user.id || localStorage.getItem('userId') || null;
        const { data } = await axios.get(`/news/news/of/user`, {
          params: { current: this.current, id: 1 },
          headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
        });
        if (data && data.success && Array.isArray(data.data)) {
          const newNewss = data.data.map((b) => ({
            ...b,
            img: this.formatImageUrl(b.images),
            icon: this.formatImageUrl(b.icon),
          }));
          this.newss = [...this.newss, ...newNewss];
          this.current++;
        } else {
          this.$message.error(data.msg || '获取新闻列表失败');
        }
      } catch (err) {
        this.$message.error(err.response?.data?.msg || err.message || '获取新闻列表失败');
      } finally {
        this.isReachBottom = false;
      }
    },
    goToNewsDetail(id) {
      this.$router.push(`/news-detail/${id}`);
    },
    onScroll(e) {
      const { scrollTop, offsetHeight, scrollHeight } = e.target;
      if (scrollTop + offsetHeight >= scrollHeight - 20 && !this.isReachBottom) {
        this.queryHotNewsScroll();
      }
    },
    toggleMenu() {
      this.isMenuOpen = !this.isMenuOpen;
    },
    closeMenuOnClickOutside(event) {
      const menu = this.$refs.userMenu;
      if (menu && !menu.contains(event.target)) {
        this.isMenuOpen = false;
      }
    },
    goToProfile() {
      this.$router.push('/user-information');
      this.isMenuOpen = false;
    },
    async logout() {
      try {
        await axios.post('/users/user/logout', {}, {
          headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
        });
        sessionStorage.removeItem('token');
        localStorage.removeItem('token');
        localStorage.removeItem('userId');
        window.location.href = '/';
      } catch (err) {
        this.$message.error(err.response?.data?.msg || err.message || '退出登录失败');
      }
    },
    async queryUser() {
      try {
        const { data } = await axios.get('/users/user/me', {
          headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
        });
        if (data.success && data.data) {
          this.user = {
            ...data.data,
            icon: this.formatImageUrl(data.data.icon),
            id: data.data.id || localStorage.getItem('userId'),
          };
          localStorage.setItem('userId', this.user.id);
          this.queryUserInfo();
        }
      } catch (err) {
        this.$message.error(err.response?.data?.msg || err.message || '获取用户信息失败');
      }
    },
    queryUserInfo() {
      axios
        .get(`/users/user/basic`, {
          params: { userId: this.user.id || localStorage.getItem('userId') },
        })
        .then(({ data }) => {
          this.info = data || { introduce: '' };
          sessionStorage.setItem('userInfo', JSON.stringify(data));
        })
        .catch(err => this.$message.error(err.message));
    },
    handleImageError(event) {
      event.target.src = this.defaultIcon;
    },
  },
};
</script>

<style scoped>
.container.dark-theme {
  background: radial-gradient(ellipse at center, #001e3c 0%, #000 100%);
  min-height: 100vh;
  color: #e0e0e0;
  font-family: 'Microsoft YaHei', sans-serif;
}
.header {
  display: flex;
  justify-content: space-between;
  padding: 10px 30px;
  background: #002d52;
  align-items: center;
}
.header .logo {
  font-size: 20px;
  color: #4fc3f7;
}
.header .nav a {
  margin: 0 10px;
  color: #e0e0e0;
  text-decoration: none;
}
.user-menu {
  position: relative;
}
.avatar-box {
  display: inline-block;
}
.avatar-box img.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 2px solid #4fc3f7;
  object-fit: cover;
}

.avatar-publisher-box img.avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 2px solid #4fc3f7;
  object-fit: cover;
}
.dropdown-menu {
  position: absolute;
  top: 50px;
  right: 0;
  background: #002d52;
  border: 1px solid #4fc3f7;
  border-radius: 4px;
  z-index: 10;
}
.menu-item {
  padding: 10px;
  color: #e0e0e0;
  cursor: pointer;
}
.menu-item:hover {
  background: #014b75;
}
.screen {
  padding: 20px;
}
.right-section {
  flex: 1;
  max-width: 800px;
  margin: 0 auto;
}
.section-title {
  font-size: 24px;
  font-weight: bold;
  color: #4fc3f7;
  margin-bottom: 30px;
  text-align: center;
}
.news-list {
  max-height: calc(100vh - 180px);
  overflow-y: auto;
  background: #012c4a;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 0 15px rgba(30, 136, 229, 0.5);
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.news-list::-webkit-scrollbar {
  display: none;
}
.news-item {
  display: flex;
  margin-bottom: 25px;
  padding: 15px;
  background: #003b64;
  border-radius: 8px;
  box-shadow: 0 0 12px rgba(41, 182, 246, 0.6);
  transition: transform 0.2s ease-in-out;
  cursor: pointer;
}
.news-item:hover {
  transform: translateY(-3px);
}
.news-item img {
  width: 120px;
  height: 120px;
  object-fit: cover;
  border-radius: 4px;
  margin-right: 15px;
  flex-shrink: 0;
}
.news-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.news-content h3 {
  margin: 0 0 8px;
  font-size: 18px;
  color: #e0e0e0;
  line-height: 1.4;
}
.news-content p {
  margin: 0 0 10px;
  color: #b0bec5;
  font-size: 14px;
  line-height: 1.6;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}
.publisher-info {
  display: flex;
  align-items: center;
  margin-top: 8px;
}
.publisher-name {
  font-size: 14px;
  color: #e0e0e0;
  margin-left: 8px;
}
.loading {
  text-align: center;
  padding: 15px;
  color: #b0bec5;
  font-size: 16px;
}
</style>
```
